#include "usermodel.hpp" // 对ORM操作的头文件
#include "db.h"          // 数据层的操作头文件

#include <sstream>
#include <iostream>
#include <memory> // for std::unique_ptr<>
using namespace std;

// RAII辅助管理(MYSQL_RES *)
class MySQLResult
{
public:
    MySQLResult(MYSQL_RES *result) : res_(result) {}
    ~MySQLResult()
    {
        if (res_)
            mysql_free_result(res_);
    } // 会在析构之前释放结果集
    MYSQL_ROW fetch_row() { return mysql_fetch_row(res_); }

    // 支持移动语义
    MySQLResult(MySQLResult &&other) noexcept : res_(other.res_) { other.res_ = nullptr; }
    MySQLResult &operator=(MySQLResult &&other) noexcept
    {
        std::swap(res_, other.res_);
        return *this;
    }

private:
    // 防止拷贝
    MySQLResult(const MySQLResult &) = delete;
    MySQLResult &operator=(const MySQLResult &) = delete;

    MYSQL_RES *res_;
};

/**
 * 该User表中的name字段NOT NULL 和 UNIQUE唯一性、 password字段有NOT NULL 非空
 * usermodel只负责数据库的CRUD， 不管业务逻辑
 */
// User表的Add方法, 例如：向表中增加信息
bool UserModel::insert(User &user)
{
    // 1.组织sql语句
    // char sql[128] = {0};
    // sprintf(sql, "insert into User(name, password, state) values('%s', '%s', '%s')",
    //     user.getName().c_str(), user.getPwd().c_str(), user.getState().c_str());

    // 使用 ostringstream 构建 SQL 语句
    std::ostringstream sql;
    sql << "INSERT INTO User (name, password, state) VALUES ('"
        << user.getName() << "', '"
        << user.getPwd() << "', '"
        << user.getState() << "')";

    // 定义一个db::MySQL obj   注意不是MYSQL 而是MySQL
    MySQL mysql;
    // 调用db::MySQL::connect()::mysql_real_connect()连接数据库
    if (mysql.connect())
    {
        if (mysql.update(sql.str())) // std::ostringstream::str()获取字符串
        {
            // 获取插入成功的用户数据生成的PRIMARY ID
            uint64_t insertId = mysql.getLastInsertId();
            std::cout << "Inserted record with ID: " << insertId << std::endl;

            // 可选：将插入的ID保存到用户对象或其他需要的地方
            user.setId(insertId);

            // 连接成功 且 mysql_query()成功
            return true;
        }
        else
        {
            // 连接成功但mysql_query（）失败
            return false;
        }
    }
    else
    {
        // 连接数据库失败
        return false;
    }
}

// 查找用户，假设一定能找到用户，否则抛出异常
std::unique_ptr<User> UserModel::find(const int &id)
{
    // 1.组织sql语句
    std::ostringstream sql;
    // ps:注册table_name大小写
    sql << "SELECT * FROM User WHERE id = " << id;

    // 2.通过ORM操作类连接数据库
    MySQL mysql;
    if (mysql.connect())
    {
        // 3.获取结果集
        MYSQL_RES *raw_res = mysql.query(sql.str());
        if (raw_res != nullptr)
        {
            // 4.使用 RAII 来管理 结果集 的生命周期
            MySQLResult res(raw_res);
            // 5.处理查询结果
            MYSQL_ROW row = res.fetch_row();
            if (row != nullptr)
            {
                // 6.如果找到了用户，创建一个临时的 User 对象并填充数据
                auto user = std::make_unique<User>();
                user->setId(std::stoi(row[0]));
                user->setName(row[1]);
                user->setPwd(row[2]);
                user->setState(row[3]);
                // 7.返回用户
                return user;
            }
        }
    } // end of if (mysql.connect())
    // 如果没有找到用户，则返回ID为-1的默认User对象
    return std::make_unique<User>();
}

// 更新用户状态信息
bool UserModel::updateState(const User &user)
{
    // 1.准备预处理语句
    std::ostringstream sql;
    sql << "UPDATE User SET state = ? WHERE id = ?";

    // 2.数据库操作类连接数据库
    MySQL mysql;
    if (!mysql.connect())
    {
        return false;
    }

    // 3.准备预处理语句
    MYSQL_STMT *stmt = mysql.prepare(sql.str());
    if (stmt == nullptr)
    {                       // 检查预处理语句是否准备成功
        mysql.disconnect(); // 断开数据库连接
        return false;
    }

    // 4.绑定参数
    MYSQL_BIND bind_param[2];
    memset(bind_param, 0, sizeof(bind_param));
    // 绑定第一个参数：state
    std::string state = user.getState();
    bind_param[0].buffer_type = MYSQL_TYPE_STRING;
    bind_param[0].buffer = const_cast<char *>(state.c_str());
    bind_param[0].buffer_length = state.size(); // 缓冲区大小

    bind_param[0].length = &bind_param[0].buffer_length;
    // 绑定第二个参数：id
    int32_t userId = user.getId();
    bind_param[1].buffer_type = MYSQL_TYPE_LONG;
    bind_param[1].buffer = &userId;

    // 4.1如果绑定参数失败，立即返回
    if (!mysql.bindParam(bind_param))
    {
        mysql.closeStmt();
        mysql.disconnect();
        return false;
    }

    // 5.执行预处理语句
    if (!mysql.execute())
    {
        mysql.disconnect();
        return false; // 如果执行失败，立即返回
    }

    // 6.关闭预处理语句 & 断开数据库连接
    mysql.closeStmt();
    mysql.disconnect();
    return true;
}

// 重置用户的状态信息为offline
void UserModel::resetState()
{
    // 1.组织sql语句
    std::ostringstream sql;
    sql << "update User set state = 'offline' where state = 'online'";

    MySQL mysql;
    if (mysql.connect())
    {
        mysql.update(sql.str());
    }
}

// // 更新用户状态信息
// bool UserModel::updateState(const User &user) {
//     // 1.准备预处理语句
//     std::ostringstream sql;
//     sql << "UPDATE User SET state = " << user.getState() << "WHERE id = " << user.getId();

//     MySQL mysql;
//     if (mysql.connect()) {
//         if (mysql.update(sql.str())) {
//             return true;
//         }
//     }

//     return false;
// }

// {"msgid":1, "id":15, "password":"123789"}
